﻿using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Text;
using System.Web;

namespace SharePointAccessMonitor.Models
{
    public static class LogUtil
    {
        class GroupLogContext
        {
            private string group { get; set; }

            private StreamWriter traceWriter { get; set; }

            private DateTime currentDate { get; set; }

            private Object lockObject = new object();

            public GroupLogContext(string group)
            {
                this.group = HttpUtility.UrlEncode(group);
            }

            private string CurrentFileName()
            {
                return Path.Combine(LogUtil.LogDirectory, string.Format("access_{0}_{1:yyyyMMdd}.log", group, currentDate));
            }
            public void WriteLog(LogItem item)
            {
                if (currentDate != DateTime.Today)
                {
                    if (traceWriter != null)
                    {
                        traceWriter.Close();
                        traceWriter = null;
                    }
                    currentDate = DateTime.Today;
                }
                if (traceWriter == null)
                { 
                    traceWriter = new StreamWriter(CurrentFileName(), true);
                    traceWriter.AutoFlush = true;
                }
                traceWriter.WriteLine(item.ToString());
            }

            public IEnumerable<LogItem> GetLog(DateTime from, DateTime to)
            {
                if (!Directory.Exists(LogDirectory)) Directory.CreateDirectory(LogDirectory);
                foreach (var file in Directory.GetFiles(LogDirectory, "access_" + group + "_*.log"))
                {
                    Trace.WriteLine("GetLog found file " + file);
                    var dateString = Path.GetFileNameWithoutExtension(file).Replace("access_" + group + "_", "");
                    DateTime d;
                    if (DateTime.TryParseExact(dateString, "yyyyMMdd", null, DateTimeStyles.None, out d))
                    {
                        if (d >= from.Date && d <= to)
                        {

                            using (FileStream fs = new FileStream(file, FileMode.Open, FileAccess.Read, FileShare.ReadWrite))
                            {
                                using (TextReader sr = new StreamReader(fs))
                                {
                                    string line;
                                    while ((line = sr.ReadLine()) != null)
                                    {
                                        var log = LogItem.Parse(line);
                                        if (log.Timestamp >= from && log.Timestamp < to) yield return log;
                                    }
                                }
                            }
                        }
                    }
                }
            }

        }

        public static string LogDirectory { get; set; }

        private static object lockObject = new object();

        private static Dictionary<string, GroupLogContext> contexts = new Dictionary<string, GroupLogContext>(); 


        public static void WriteLog(string group, LogItem item)
        {
            if (!contexts.ContainsKey(group))
            {
                lock(lockObject)
                {
                    contexts.Add(group, new GroupLogContext(group));
                }
            }
            contexts[group].WriteLog(item);
        }


        public static IEnumerable<LogItem> GetLog(string group, DateTime from, DateTime to)
        {
            if (!Directory.Exists(LogDirectory)) Directory.CreateDirectory(LogDirectory);

            if (!contexts.ContainsKey(group))
            {
                lock (lockObject)
                {
                    contexts.Add(group, new GroupLogContext(group));
                }
            }
            Trace.WriteLine(string.Format("GetLog group:{0} from:{2} to:{2}", group, from, to));

            return contexts[group].GetLog(from, to);
        }
    }
}